package com.jarveis.dbs.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;

import com.jarveis.dbs.core.bean.CallBean;
import com.jarveis.dbs.core.bean.ConstantBean;
import com.jarveis.dbs.core.bean.DbsBean;
import com.jarveis.dbs.core.bean.FilterBean;
import com.jarveis.dbs.core.bean.FunctionBean;
import com.jarveis.dbs.core.filter.Filter;
import com.jarveis.frame.io.Resource;
import com.jarveis.frame.lang.CharacterUtil;
import com.jarveis.frame.lang.StringUtil;

/**
 * @desc DB上下文
 * @author liuguojun
 * @create 2014-12-23
 */
public class DBContext {

	private static final Logger logger = Logger.getLogger(DBContext.class);

	private static final String CONFIG_PATH = "dbs.xml";

	private static Map<String, FunctionBean> functionStore = new HashMap<String, FunctionBean>();
	private static DbsBean dbsBean = new DbsBean();
	private volatile static DBContext instance = null;

	/**
	 * 初始化配置
	 */
	private DBContext() {
		init(CONFIG_PATH);
	}

	/**
	 * 初始化配置
	 * 
	 * @param filePath
	 */
	private void init(String filePath) {
		try {
			parseConfig(filePath);
		} catch (Exception ex) {
			logger.error("加载数据源出错！", ex);
		}
	}

	/**
	 * 设置配置文件
	 * 
	 * @param filePath
	 * @throws Exception
	 */
	private void parseConfig(String filePath) throws Exception {
		Document document = Jsoup.parse(Resource.getStream(filePath),
				CharacterUtil.UTF8, "", Parser.xmlParser());

		// 初始化过滤配置集合
		if (dbsBean.getFilters() == null) {
			dbsBean.setFilters(new ArrayList<FilterBean>());
		}
		Elements filters = document.select("filters > filter");
		for (Element filter : filters) {
			FilterBean filterBean = parseFilter(filter);
			if (filterBean != null) {
				dbsBean.getFilters().add(filterBean);
			}
		}

		// 初始化功能配置集合
		if (dbsBean.getFunctions() == null) {
			dbsBean.setFunctions(new ArrayList<FunctionBean>());
		}
		Elements functions = document.select("functions > function");
		for (Element function : functions) {
			FunctionBean functionBean = parseFunction(function);
			if (functionBean != null) {
				dbsBean.getFunctions().add(functionBean);
			}
		}

		// 初始化常量配置集合
		if (dbsBean.getConstants() == null) {
			dbsBean.setConstants(new ArrayList<ConstantBean>());
		}
		Elements constants = document.select("constants > constant");
		for (Element constant : constants) {
			ConstantBean constantBean = parseConstant(constant);
			if (constantBean != null) {
				dbsBean.getConstants().add(constantBean);
			}
		}

	}

	/**
	 * 解析常量配置
	 * 
	 * @param element
	 * @throws Exception
	 */
	private ConstantBean parseConstant(Element element) {
		String name = element.attr("name");
		String value = element.attr("value");

		ConstantBean constantBean = new ConstantBean();
		constantBean.setName(name);
		constantBean.setValue(value);

		ConstantFactory.put(name, value);

		return constantBean;
	}

	/**
	 * 解析功能配置
	 * 
	 * @param element
	 * @throws Exception
	 */
	private FunctionBean parseFunction(Element element) throws Exception {
		String code = element.attr("code");
		String init = element.attr("init");
		String desc = element.attr("desc");
		String clazz = element.attr("clazz");

		if (StringUtil.isEmpty(clazz)) {
			logger.info(code + "未定义clazz属性");
			return null;
		}

		Object service = ReflectionUtils.newInstance(clazz);
		if (service == null) {
			logger.info(clazz + "未能实例化！");
			return null;
		}

		if (!(service instanceof Service)) {
			logger.info(clazz + "未实现 com.jarveis.dbs.core.Service接口");
			return null;
		}

		FunctionBean functionBean = new FunctionBean();
		functionBean.setCode(code);
		functionBean.setInit(init);
		functionBean.setDesc(desc);
		functionBean.setClazz(clazz);
		functionBean.setCalls(new ArrayList<CallBean>());
		Elements calls = element.select("calls > call");
		for (Element call : calls) {
			functionBean.getCalls().add(parseCall(call));
		}

		functionStore.put(code, functionBean);
		ServiceFactory.putService(code, (Service) service);

		return functionBean;
	}

	/**
	 * 解析功能调用配置
	 * 
	 * @param element
	 * @return
	 */
	private CallBean parseCall(Element element) throws Exception {
		String code = element.attr("code");
		String sync = element.attr("sync");

		CallBean callBean = new CallBean();
		callBean.setCode(code);
		callBean.setSync(Boolean.parseBoolean(sync));

		return callBean;
	}

	/**
	 * 解析过滤器配置
	 * 
	 * @param element
	 * @throws Exception
	 */
	private FilterBean parseFilter(Element element) throws Exception {
		String id = element.attr("id");
		String clazz = element.attr("clazz");
		String type = element.attr("type");
		String match = element.attr("match");

		if (StringUtil.isEmpty(clazz)) {
			logger.info(id + "未定义clazz属性");
			return null;
		}

		Object filter = ReflectionUtils.newInstance(clazz);
		if (filter == null) {
			logger.info(clazz + "未能实例化！");
			return null;
		}
		if (!(filter instanceof Filter)) {
			logger.info(clazz + "未实现 com.jarveis.dbs.core.filter.Filter接口");
			return null;
		}
		// 初始化过滤器
		((Filter) filter).init();

		FilterBean filterBean = new FilterBean();
		filterBean.setId(id);
		filterBean.setClazz(clazz);
		filterBean.setType(type);
		filterBean.setMatch(match);

		FilterFactory.put(id, (Filter) filter);

		return filterBean;
	}

	/**
	 * 
	 * @return
	 */
	public static DBContext getInstance() {
		if (instance == null) {
			synchronized (DBContext.class) {
				if (instance == null) {
					instance = new DBContext();
				}
			}
		}
		return instance;
	}

	/**
	 * 获取功能配置
	 * 
	 * @param code
	 * @return
	 */
	public FunctionBean getFunction(String code) {
		return functionStore.get(code);
	}

	/**
	 * 获取过滤器配置集合
	 * 
	 * @return
	 */
	public List<FilterBean> getFilters() {
		return dbsBean.getFilters();
	}

}
